package br.edu.unifei.mestrado.unfold.mn;

import java.util.ArrayList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import br.edu.unifei.mestrado.commons.graph.GraphWrapper;
import br.edu.unifei.mestrado.commons.graph.NodeWrapper;
import br.edu.unifei.mestrado.commons.graph.RelationshipWrapper;
import br.edu.unifei.mestrado.commons.mn.TempRelationships;

public class SetMatchingRemaining extends SetMatching {


	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	//***************************************************************************************************
	//DAQUI PARA BAIXO SÃO MÉTODOS PARA TRATAR AS ARESTAS REMANECENTES APÓS A CONTRAÇÃO DE TODOS OS NODES
	//***************************************************************************************************
	
	/*
	 * Processa os vertices que não foram emparelhados. Repassa os vertices não processados e suas respectivas
	 * arestas
	 */
	public void processRemainingVertices(GraphWrapper newGraph, int setId, Iterable<NodeWrapper> nodes,
			Iterable<RelationshipWrapper> setEdgeCutList) {

		int i = 0;
		for (NodeWrapper oldNode : nodes) {
				logger.debug("Repassando vertice: " + oldNode.getId());
				// cria um novo, para não usar a mesma instancia do grafo anterior
				NodeWrapper newVertice = newGraph.createNode(oldNode.getId(), oldNode.getWeight());

				ArrayList<TempRelationships> newArestas = new ArrayList<TempRelationships>();

				// passa o node, pq ele tem as arestas. O newVertice ainda não tem arestas.
				addArestasFromRemainingVertex(oldNode, newVertice, newArestas);
				imprimeArestasTmp(newArestas);

				handleRemainingArestasParalelas(newArestas);
				imprimeArestasTmp(newArestas);

				for (TempRelationships edge : newArestas) {
					// adiciona a aresta no grafo
					newGraph.createChain(edge.getId(), edge.getWeight(), edge.getStartNode(), edge
							.getwStartNode(), edge.getEndNode(), edge.getwEndNode());
				}
				i++;
		}
		logger.info("Qtd nodes Coarsed repassados: " + i);
	}

	/*
	 * Adiciona as arestas dos vertices que não foram emparelhados.
	 */
	private void addArestasFromRemainingVertex(NodeWrapper oldV, NodeWrapper newVertice,
			ArrayList<TempRelationships> newArestas) {
		// UTIL: peso de um nó que já existe. só coloquei ele para reaproveitar a função do createChain
		int weightFake = 1;
		// for para adicionar as arestas de oldV
		for (RelationshipWrapper arestaTmp : oldV.getRelationships()) {
			if (arestaTmp.getId() == 19982) {
				System.out.println("addArestasFromVertex 19982");
			}
			NodeWrapper other = arestaTmp.getOtherNode(oldV);
			long otherId = other.getId();
			// if (other.hasInsideOf()) {
			if (hasInsideOf(other)) {
				// se o vertice já foi contraido, então pega o vertice correspondente
				// otherId = other.getInsideOf();
				otherId = getInsideOf(other);
			} else {
				logger.error("Verificar !!!, não pode ter 2 vértices adjacentes sem emparelhar oldV: "
						+ oldV.getId() + " other: " + other.getId());
				// TODO: Verificar se realmente deve descartar a aresta para si mesmo.
				// não para o processamento
			}
			// o newVertice sempre vai na ponta A.
			TempRelationships newEdge = new TempRelationships(arestaTmp.getId(), arestaTmp.getWeight(),
					newVertice.getId(), newVertice.getWeight(), otherId, weightFake);

			// add aresta
			newArestas.add(newEdge);
		}
	}

	/*
	 * Processa as arestas paralelas dos vertices restantes.
	 */
	private void handleRemainingArestasParalelas(ArrayList<TempRelationships> newArestas) {
		ArrayList<TempRelationships> arestasToRemove = new ArrayList<TempRelationships>();
		// loop para ver se tem 2 arestas paralelas
		//TODO: melhorar essa logica quadratica
		for (int i = 0; i < newArestas.size(); ++i) {
			TempRelationships are1 = newArestas.get(i);
			for (int k = i + 1; k < newArestas.size(); ++k) {
				TempRelationships are2 = newArestas.get(k);

				// UTIL: usa o vb, pois o va é sempre o vertice novo
				if (are1.getEndNode() == are2.getEndNode()) {

					// se o vb for o mesmo, então a aresta e paralela
					int peso = are1.getWeight() + are2.getWeight();

					// cria uma aresta nova
					TempRelationships coarsedEdge = new TempRelationships(are1.getId(), peso, are1
							.getStartNode(), are1.getwStartNode(), are1.getEndNode(), are1.getwEndNode());

					// substitui a aresta j
					newArestas.set(i, coarsedEdge);

					// remove a aresta k (are2)
					arestasToRemove.add(are2);
				}
			}
		}
		newArestas.removeAll(arestasToRemove);
	}
}
